package org.scohen.juploadr.app.tags;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StyleRange;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.custom.TextChangeListener;
import org.eclipse.swt.custom.TextChangedEvent;
import org.eclipse.swt.custom.TextChangingEvent;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Decorations;
import org.scohen.juploadr.app.ImageAttributes;
import org.scohen.juploadr.ui.PopupData;
import org.scohen.juploadr.ui.PopupHandler;
import org.scohen.juploadr.ui.ReusableUIFactory;


public class TagPainter extends MouseAdapter implements TextChangeListener {
    private Map<String, Integer> map = new HashMap<String, Integer>();
    private List<ImageAttributes> atts;
    private StyledText st;
    private static Pattern p = Pattern.compile("\"([^\"]+)\"|\\b(\\w+)\\b");
    private TagPopupHandler handler;

    public TagPainter(StyledText st, List<ImageAttributes> atts) {
        this.atts = atts;
        this.st = st;
        rebuildTagInfo();
        handler = new TagPopupHandler(st.getShell());
    }

    /**
     * @param atts
     */
    private void rebuildTagInfo() {
        map.clear();
        for (ImageAttributes ia : atts) {
            for (Tag t : ia.getTags()) {
                String tagString = t.toString();
                if (map.get(tagString) == null) {
                    map.put(tagString, 1);
                } else {
                    map.put(tagString, map.get(tagString) + 1);
                }
            }
        }
    }

    public void modifyText(ModifyEvent e) {
        paintTags();
    }

    public void textChanged(TextChangedEvent event) {
        paintTags();
    }

    public void textChanging(TextChangingEvent event) {
        // TODO Auto-generated method stub

    }

    public void textSet(TextChangedEvent event) {
        paintTags();
    }

    public void paintTags() {
        st.setStyleRange(null);
        Matcher m = p.matcher(st.getText());
        while (m.find()) {
            String tag = m.group();
            if (!tagAppliesToAll(tag)) {
                StyleRange sr = new StyleRange(m.start(), tag.length(), ReusableUIFactory.getInstance()
                        .getDisabledTextColor(), null);
                st.setStyleRange(sr);
            }
        }
    }

    public void mouseDown(MouseEvent event) {
        if (event.button == 3 || (event.stateMask == SWT.CTRL && event.button == 1)) {
            Point click = new Point(event.x, event.y);
            Point size = st.computeSize(SWT.DEFAULT, SWT.DEFAULT);
            if (click.x <= size.x && click.y <= size.y) {
                int offset = st.getOffsetAtLocation(click);
                Matcher m = p.matcher(st.getText());
                while (m.find()) {
                    String tag = m.group().trim();
                      if (m.start() <= offset && m.end() >= offset) {
                        if (tag.length() > 0 && !tagAppliesToAll(tag)) {
                            handler.setTag(tag.trim());
                            handler.setEnabled(true);
                        } else {
                            handler.setTag(null);
                            handler.setEnabled(false);
                        }
                    }
                }
            }
        }

    }

    public boolean tagAppliesToAll(Tag tag) {
        return tagAppliesToAll(tag.toString());
    }
    
    public boolean tagAppliesToAll(String tag) {
        return map.get(tag) == null || map.get(tag) == atts.size();
    }

    private void applyTagToAll(String tag) {
        Tag t = new Tag(tag);
        for (ImageAttributes ia : atts) {
            ia.getTags().add(t);
        }
        rebuildTagInfo();
        paintTags();
    }

    private class TagPopupHandler extends PopupHandler {
        private PopupData data;
        private String tag;

        protected TagPopupHandler(Decorations parent) {
            super(parent);

        }

        private static final String APPLY_TO_ALL = "Apply to all";

        @Override
        protected void regenerateOptions() {
            options = new LinkedList<PopupData>();
            data = new PopupData(APPLY_TO_ALL, true);
            options.add(data);
        }

        @Override
        protected void widgetSelected(SelectionEvent event) {
            TagPainter.this.applyTagToAll(tag);
        }

        public void setEnabled(boolean enabled) {
            if (enabled) {
                show();
            }
        }

        public void setTag(String tag) {
            this.tag = tag;
        }

    }

}
